/*     */ package com.zimbra.cs.store.file;
/*     */ 
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.FileCache;
/*     */ import com.zimbra.common.util.FileCache.Builder;
/*     */ import com.zimbra.common.util.FileUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.SystemUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.store.Blob;
/*     */ import com.zimbra.cs.store.BlobBuilder;
/*     */ import com.zimbra.cs.store.BlobInputStream;
/*     */ import com.zimbra.cs.store.FileDescriptorCache;
/*     */ import com.zimbra.cs.store.IncomingDirectory;
/*     */ import com.zimbra.cs.store.MailboxBlob;
/*     */ import com.zimbra.cs.store.MailboxBlob.MailboxBlobInfo;
/*     */ import com.zimbra.cs.store.StagedBlob;
/*     */ import com.zimbra.cs.store.StoreManager;
/*     */ import com.zimbra.cs.store.StoreManager.StoreFeature;
/*     */ import com.zimbra.cs.volume.Volume;
/*     */ import com.zimbra.cs.volume.VolumeManager;
/*     */ import com.zimbra.znative.IO;
/*     */ import java.io.File;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class FileBlobStore
/*     */   extends StoreManager
/*     */ {
/*  47 */   private static final VolumeManager MANAGER = VolumeManager.getInstance();
/*     */   
/*     */   public void startup() throws IOException, ServiceException
/*     */   {
/*  51 */     IncomingDirectory.startSweeper();
/*     */     
/*     */ 
/*  54 */     File tmpDir = new File(LC.zimbra_tmp_directory.value());
/*  55 */     File ufCacheDir = new File(tmpDir, "uncompressed");
/*  56 */     FileUtil.ensureDirExists(ufCacheDir);
/*  57 */     FileCache<String> ufCache = FileCache.Builder.createWithStringKey(ufCacheDir, false).minLifetime(LC.uncompressed_cache_min_lifetime.longValue()).build();
/*     */     
/*  59 */     BlobInputStream.setFileDescriptorCache(new FileDescriptorCache(ufCache).loadSettings());
/*     */   }
/*     */   
/*     */   public void shutdown()
/*     */   {
/*  64 */     IncomingDirectory.stopSweeper();
/*  65 */     BlobInputStream.getFileDescriptorCache().shutdown();
/*     */   }
/*     */   
/*     */   public boolean supports(StoreManager.StoreFeature feature)
/*     */   {
/*  70 */     switch (feature) {
/*  71 */     case BULK_DELETE:  return true;
/*  72 */     case CENTRALIZED:  return false;
/*  73 */     case SINGLE_INSTANCE_SERVER_CREATE:  return false;
/*  74 */     case RESUMABLE_UPLOAD:  return false; }
/*  75 */     return false;
/*     */   }
/*     */   
/*     */   private Blob getUniqueIncomingBlob() throws IOException, ServiceException
/*     */   {
/*  80 */     Volume volume = MANAGER.getCurrentMessageVolume();
/*  81 */     IncomingDirectory incdir = volume.getIncomingDirectory();
/*  82 */     if (incdir == null) {
/*  83 */       throw ServiceException.FAILURE("storing blob to volume without incoming directory: " + volume.getName(), null);
/*     */     }
/*  85 */     File f = incdir.getNewIncomingFile();
/*  86 */     ensureParentDirExists(f);
/*  87 */     return new VolumeBlob(f, volume.getId());
/*     */   }
/*     */   
/*     */   public BlobBuilder getBlobBuilder() throws IOException, ServiceException
/*     */   {
/*  92 */     Blob blob = getUniqueIncomingBlob();
/*  93 */     return new VolumeBlobBuilder(blob);
/*     */   }
/*     */   
/*     */   public Blob storeIncoming(InputStream in, boolean storeAsIs)
/*     */     throws IOException, ServiceException
/*     */   {
/*  99 */     BlobBuilder builder = getBlobBuilder();
/*     */     
/* 101 */     builder.disableCompression(storeAsIs).disableDigest(storeAsIs);
/*     */     
/* 103 */     return builder.init().append(in).finish();
/*     */   }
/*     */   
/*     */ 
/*     */   public VolumeStagedBlob stage(InputStream in, long actualSize, Mailbox mbox)
/*     */     throws IOException, ServiceException
/*     */   {
/* 110 */     Blob blob = storeIncoming(in);
/* 111 */     return new VolumeStagedBlob(mbox, (VolumeBlob)blob).markStagedDirectly();
/*     */   }
/*     */   
/*     */   public VolumeStagedBlob stage(Blob blob, Mailbox mbox)
/*     */     throws IOException
/*     */   {
/* 117 */     return new VolumeStagedBlob(mbox, (VolumeBlob)blob);
/*     */   }
/*     */   
/*     */   public VolumeMailboxBlob copy(MailboxBlob src, Mailbox destMbox, int destItemId, int destRevision)
/*     */     throws IOException, ServiceException
/*     */   {
/* 123 */     Volume volume = MANAGER.getCurrentMessageVolume();
/*     */     
/* 125 */     return link(src.getLocalBlob(), destMbox, destItemId, destRevision, volume.getId());
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public VolumeMailboxBlob copy(Blob src, Mailbox destMbox, int destItemId, int destRevision, short destVolumeId)
/*     */     throws IOException, ServiceException
/*     */   {
/* 143 */     Volume volume = MANAGER.getVolume(destVolumeId);
/* 144 */     return copy(src, destMbox, destItemId, destRevision, volume);
/*     */   }
/*     */   
/*     */   private VolumeMailboxBlob copy(Blob src, Mailbox destMbox, int destItemId, int destRevision, Volume destVolume) throws IOException, ServiceException
/*     */   {
/* 149 */     File srcFile = src.getFile();
/* 150 */     if (!srcFile.exists()) {
/* 151 */       throw new IOException(srcFile.getPath() + " does not exist");
/*     */     }
/*     */     
/* 154 */     String srcPath = src.getPath();
/* 155 */     File dest = getMailboxBlobFile(destMbox, destItemId, destRevision, destVolume.getId(), false);
/* 156 */     BlobInputStream.getFileDescriptorCache().remove(dest.getPath());
/* 157 */     String destPath = dest.getAbsolutePath();
/*     */     
/* 159 */     if (ZimbraLog.store.isDebugEnabled()) {
/* 160 */       long srcSize = srcFile.length();
/* 161 */       long srcRawSize = src.getRawSize();
/* 162 */       ZimbraLog.store.debug("Copying %s (size=%d, raw size=%d) to %s for mailbox %d, id %d.", new Object[] { srcPath, Long.valueOf(srcSize), Long.valueOf(srcRawSize), destPath, Integer.valueOf(destMbox.getId()), Integer.valueOf(destItemId) });
/*     */     }
/*     */     
/*     */ 
/* 166 */     ensureParentDirExists(dest);
/*     */     boolean destCompressed;
/*     */     boolean destCompressed;
/* 169 */     if (destVolume.isCompressBlobs()) { boolean destCompressed;
/* 170 */       if ((src.isCompressed()) || (srcFile.length() <= destVolume.getCompressionThreshold())) {
/* 171 */         FileUtil.copy(srcFile, dest, !DebugConfig.disableMessageStoreFsync);
/* 172 */         destCompressed = src.isCompressed();
/*     */       } else {
/* 174 */         FileUtil.compress(srcFile, dest, !DebugConfig.disableMessageStoreFsync);
/* 175 */         destCompressed = true;
/*     */       }
/*     */     } else {
/* 178 */       if (src.isCompressed()) {
/* 179 */         FileUtil.uncompress(srcFile, dest, !DebugConfig.disableMessageStoreFsync);
/*     */       } else {
/* 181 */         FileUtil.copy(srcFile, dest, !DebugConfig.disableMessageStoreFsync);
/*     */       }
/* 183 */       destCompressed = false;
/*     */     }
/*     */     
/* 186 */     VolumeBlob newBlob = (VolumeBlob)new VolumeBlob(dest, destVolume.getId()).copyCachedDataFrom(src).setCompressed(destCompressed);
/* 187 */     return new VolumeMailboxBlob(destMbox, destItemId, destRevision, destVolume.getLocator(), newBlob);
/*     */   }
/*     */   
/*     */   public VolumeMailboxBlob link(StagedBlob src, Mailbox destMbox, int destItemId, int destRevision)
/*     */     throws IOException, ServiceException
/*     */   {
/* 193 */     Volume volume = MANAGER.getCurrentMessageVolume();
/* 194 */     VolumeBlob blob = ((VolumeStagedBlob)src).getLocalBlob();
/* 195 */     return link(blob, destMbox, destItemId, destRevision, volume.getId());
/*     */   }
/*     */   
/*     */   public VolumeMailboxBlob link(Blob src, Mailbox destMbox, int destItemId, int destRevision, short destVolumeId) throws IOException, ServiceException
/*     */   {
/* 200 */     File srcFile = src.getFile();
/* 201 */     if (!srcFile.exists()) {
/* 202 */       throw new IOException(srcFile.getPath() + " does not exist.");
/*     */     }
/*     */     
/* 205 */     File dest = getMailboxBlobFile(destMbox, destItemId, destRevision, destVolumeId, false);
/* 206 */     String srcPath = src.getPath();
/* 207 */     String destPath = dest.getAbsolutePath();
/* 208 */     BlobInputStream.getFileDescriptorCache().remove(destPath);
/*     */     
/* 210 */     if (ZimbraLog.store.isDebugEnabled()) {
/* 211 */       long srcSize = srcFile.length();
/* 212 */       long srcRawSize = src.getRawSize();
/* 213 */       ZimbraLog.store.debug("Linking %s (size=%d, raw size=%d) to %s for mailbox %d, id %d.", new Object[] { srcPath, Long.valueOf(srcSize), Long.valueOf(srcRawSize), destPath, Integer.valueOf(destMbox.getId()), Integer.valueOf(destItemId) });
/*     */     }
/*     */     
/*     */ 
/* 217 */     ensureParentDirExists(dest);
/*     */     
/* 219 */     short srcVolumeId = ((VolumeBlob)src).getVolumeId();
/* 220 */     if (srcVolumeId == destVolumeId) {
/*     */       try {
/* 222 */         IO.link(srcPath, destPath);
/*     */ 
/*     */       }
/*     */       catch (IOException e)
/*     */       {
/*     */ 
/* 228 */         if (dest.exists()) {
/* 229 */           File destBak = new File(destPath + ".bak");
/* 230 */           ZimbraLog.store.warn("Destination file exists.  Backing up to " + destBak.getAbsolutePath());
/* 231 */           if (destBak.exists()) {
/* 232 */             String bak = destBak.getAbsolutePath();
/* 233 */             ZimbraLog.store.warn(bak + " already exists.  Deleting to make room for new backup file");
/* 234 */             if (!destBak.delete()) {
/* 235 */               ZimbraLog.store.warn("Unable to delete " + bak);
/* 236 */               throw e;
/*     */             }
/*     */           }
/* 239 */           File destTmp = new File(destPath);
/* 240 */           if (!destTmp.renameTo(destBak)) {
/* 241 */             ZimbraLog.store.warn("Can't rename " + destTmp.getAbsolutePath() + " to .bak");
/* 242 */             throw e;
/*     */           }
/*     */           
/*     */ 
/* 246 */           IO.link(srcPath, destPath);
/*     */         } else {
/* 248 */           throw e;
/*     */         }
/*     */         
/*     */       }
/*     */       
/*     */     } else {
/* 254 */       FileUtil.copy(srcFile, dest, !DebugConfig.disableMessageStoreFsync);
/*     */     }
/* 256 */     String destLocator = Short.toString(destVolumeId);
/* 257 */     VolumeBlob vblob = (VolumeBlob)new VolumeBlob(dest, destVolumeId).copyCachedDataFrom(src);
/* 258 */     return new VolumeMailboxBlob(destMbox, destItemId, destRevision, destLocator, vblob);
/*     */   }
/*     */   
/*     */   public VolumeMailboxBlob renameTo(StagedBlob src, Mailbox destMbox, int destItemId, int destRevision)
/*     */     throws IOException, ServiceException
/*     */   {
/* 264 */     Volume volume = MANAGER.getCurrentMessageVolume();
/* 265 */     VolumeBlob blob = ((VolumeStagedBlob)src).getLocalBlob();
/* 266 */     File srcFile = blob.getFile();
/* 267 */     String srcPath = srcFile.getAbsolutePath();
/* 268 */     if (!srcFile.exists()) {
/* 269 */       throw new IOException(srcFile.getPath() + " does not exist.");
/*     */     }
/*     */     
/* 272 */     File destFile = getMailboxBlobFile(destMbox, destItemId, destRevision, volume.getId(), false);
/* 273 */     String destPath = destFile.getAbsolutePath();
/* 274 */     BlobInputStream.getFileDescriptorCache().remove(destPath);
/* 275 */     ensureParentDirExists(destFile);
/*     */     
/* 277 */     if (ZimbraLog.store.isDebugEnabled()) {
/* 278 */       long srcSize = srcFile.length();
/* 279 */       long srcRawSize = blob.getRawSize();
/* 280 */       ZimbraLog.store.debug("Renaming %s (size=%d, raw size=%d) to %s for mailbox %d, id %d.", new Object[] { srcPath, Long.valueOf(srcSize), Long.valueOf(srcRawSize), destPath, Integer.valueOf(destMbox.getId()), Integer.valueOf(destItemId) });
/*     */     }
/*     */     
/*     */ 
/* 284 */     short srcVolumeId = blob.getVolumeId();
/* 285 */     if (srcVolumeId == volume.getId()) {
/* 286 */       boolean renamed = srcFile.renameTo(destFile);
/* 287 */       if (SystemUtil.ON_WINDOWS)
/*     */       {
/*     */ 
/* 290 */         if ((!renamed) && (destFile.exists())) {
/* 291 */           destFile.delete();
/* 292 */           renamed = srcFile.renameTo(destFile);
/*     */         }
/*     */       }
/* 295 */       if (!renamed) {
/* 296 */         throw new IOException("Unable to rename " + srcPath + " to " + destPath);
/*     */       }
/*     */     } else {
/* 299 */       FileUtil.copy(srcFile, destFile, !DebugConfig.disableMessageStoreFsync);
/* 300 */       srcFile.delete();
/*     */     }
/*     */     
/* 303 */     VolumeBlob vblob = (VolumeBlob)new VolumeBlob(destFile, volume.getId()).copyCachedDataFrom(blob);
/* 304 */     return new VolumeMailboxBlob(destMbox, destItemId, destRevision, volume.getLocator(), vblob);
/*     */   }
/*     */   
/*     */   public boolean delete(MailboxBlob mblob) throws IOException
/*     */   {
/* 309 */     if (mblob == null) {
/* 310 */       return false;
/*     */     }
/* 312 */     return deleteFile(mblob.getLocalBlob().getFile());
/*     */   }
/*     */   
/*     */   public boolean delete(StagedBlob staged) throws IOException
/*     */   {
/* 317 */     VolumeStagedBlob vsb = (VolumeStagedBlob)staged;
/*     */     
/*     */ 
/* 320 */     if ((staged == null) || (!vsb.wasStagedDirectly())) {
/* 321 */       return false;
/*     */     }
/* 323 */     return deleteFile(vsb.getLocalBlob().getFile());
/*     */   }
/*     */   
/*     */   public boolean delete(Blob blob) throws IOException
/*     */   {
/* 328 */     if (blob == null) {
/* 329 */       return false;
/*     */     }
/* 331 */     return deleteFile(blob.getFile());
/*     */   }
/*     */   
/*     */   private boolean deleteFile(File file) throws IOException {
/* 335 */     if (file == null) {
/* 336 */       return false;
/*     */     }
/* 338 */     ZimbraLog.store.debug("Deleting %s.", new Object[] { file.getPath() });
/* 339 */     BlobInputStream.getFileDescriptorCache().remove(file.getPath());
/* 340 */     boolean deleted = file.delete();
/* 341 */     if (deleted) {
/* 342 */       return true;
/*     */     }
/* 344 */     if (!file.exists())
/*     */     {
/* 346 */       return false;
/*     */     }
/* 348 */     throw new IOException("Unable to delete blob file " + file.getAbsolutePath());
/*     */   }
/*     */   
/*     */   public MailboxBlob getMailboxBlob(Mailbox mbox, int itemId, int revision, String locator) throws ServiceException
/*     */   {
/* 353 */     short volumeId = Short.valueOf(locator).shortValue();
/* 354 */     File file = getMailboxBlobFile(mbox, itemId, revision, volumeId, true);
/* 355 */     if (file == null) {
/* 356 */       return null;
/*     */     }
/* 358 */     return new VolumeMailboxBlob(mbox, itemId, revision, locator, new VolumeBlob(file, volumeId));
/*     */   }
/*     */   
/*     */   public InputStream getContent(MailboxBlob mboxBlob) throws IOException
/*     */   {
/* 363 */     if (mboxBlob == null) {
/* 364 */       return null;
/*     */     }
/* 366 */     return getContent(mboxBlob.getLocalBlob());
/*     */   }
/*     */   
/*     */   public InputStream getContent(Blob blob) throws IOException
/*     */   {
/* 371 */     if (blob == null) {
/* 372 */       return null;
/*     */     }
/* 374 */     return new BlobInputStream(blob);
/*     */   }
/*     */   
/*     */   public boolean deleteStore(Mailbox mbox, Iterable<MailboxBlob.MailboxBlobInfo> blobs) throws IOException, ServiceException
/*     */   {
/* 379 */     assert (blobs == null) : "should not be passed a blob list since we support bulk blob delete";
/* 380 */     for (Volume vol : MANAGER.getAllVolumes()) {
/* 381 */       FileUtil.deleteDir(new File(vol.getMessageRootDir(mbox.getId())));
/*     */     }
/* 383 */     return true;
/*     */   }
/*     */   
/*     */   private File getMailboxBlobFile(Mailbox mbox, int itemId, int revision, short volumeId, boolean check) throws ServiceException
/*     */   {
/* 388 */     File file = new File(getBlobPath(mbox, itemId, revision, volumeId));
/* 389 */     if ((!check) || (file.exists())) {
/* 390 */       return file;
/*     */     }
/*     */     
/* 393 */     file = new File(getBlobPath(mbox, itemId, -1, volumeId));
/* 394 */     return file.exists() ? file : null;
/*     */   }
/*     */   
/*     */   public static String getBlobPath(Mailbox mbox, int itemId, int revision, short volumeId) throws ServiceException {
/* 398 */     return getBlobPath(mbox.getId(), itemId, revision, volumeId);
/*     */   }
/*     */   
/*     */   public static String getBlobPath(int mboxId, int itemId, int revision, short volumeId) throws ServiceException {
/* 402 */     Volume vol = MANAGER.getVolume(volumeId);
/* 403 */     String path = vol.getBlobDir(mboxId, itemId);
/* 404 */     int buflen = path.length() + 15 + (revision < 0 ? 0 : 11);
/*     */     
/* 406 */     StringBuilder sb = new StringBuilder(buflen);
/* 407 */     sb.append(path).append(File.separator);
/* 408 */     appendFilename(sb, itemId, revision);
/* 409 */     return sb.toString();
/*     */   }
/*     */   
/*     */   public static void appendFilename(StringBuilder sb, int itemId, int revision) {
/* 413 */     sb.append(itemId);
/* 414 */     if (revision >= 0) {
/* 415 */       sb.append('-').append(revision);
/*     */     }
/* 417 */     sb.append(".msg");
/*     */   }
/*     */   
/*     */   public static String getFilename(int itemId, int revision) {
/* 421 */     StringBuilder buf = new StringBuilder();
/* 422 */     appendFilename(buf, itemId, revision);
/* 423 */     return buf.toString();
/*     */   }
/*     */   
/*     */   private static void ensureDirExists(File dir) throws IOException {
/* 427 */     if (!FileUtil.mkdirs(dir)) {
/* 428 */       throw new IOException("Unable to create blob store directory " + dir.getAbsolutePath());
/*     */     }
/*     */   }
/*     */   
/*     */   private static void ensureParentDirExists(File file) throws IOException {
/* 433 */     ensureDirExists(file.getParentFile());
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/store/file/FileBlobStore.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */